import math

import numpy as np
import math as m


class EVAMIX:
    def __init__(self, DecisionMatrix, weight, q, o=5, c0=2):
        '''
        假设只有效益型
        :param DecisionMatrix: 决策矩阵
        :param wight: 属性权重
        :param q: q值
        :param o: 定性类别o值
        :param c0: 定量类别c值
        '''
        self.matrix = DecisionMatrix
        self.weight = weight
        self.q = q
        self.o = o
        self.c0 = c0

    def addition(self, Ivq1, Ivq2, q):
        '''
        加法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = a ** q + e ** q - (a ** q) * (e ** q)
        u2 = b ** q + f ** q - (b ** q) * (f ** q)
        v1 = c * g
        v2 = h * d
        return ([u1, u2], [v1, v2])

    def subtraction(self, Ivq1, Ivq2, q):
        '''
        减法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = a * g
        u2 = b * h
        v1 = (c ** q + e ** q - (c ** q) * (e ** q)) ** (1 / q)
        v2 = (d ** q + f ** q - (d ** q) * (f ** q)) ** (1 / q)
        return ([u1, u2], [v1, v2])

    def multiplication(self, Ivq1, Ivq2, q):
        '''
        乘法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = a * e
        u2 = b * f
        v1 = (c ** q + g ** q - (c ** q) * (g ** q)) ** (1 / q)
        v2 = (d ** q + h ** q - (d ** q) * (h ** q)) ** (1 / q)
        return ([u1, u2], [v1, v2])

    def division(self, Ivq1, Ivq2, q):
        '''
        除法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = (a ** q + g ** q - (a ** q) * (g ** q)) ** (1 / q)
        u2 = (b ** q + h ** q - (b ** q) * (h ** q)) ** (1 / q)
        v1 = c * e
        v2 = d * f
        return ([u1, u2], [v1, v2])

    def Exponentiation(self, Ivq1, q, n):
        '''
        次方运算
        :param Ivq1:
        :param q:
        :param n:开多少次方
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        u1 = a ** n
        u2 = b ** n
        v1 = (1 - ((1 - (c ** q)) ** n)) ** (1 / q)
        v2 = (1 - ((1 - (d ** q)) ** n)) ** (1 / q)
        return ([u1, u2], [v1, v2])

    def SuperiorityRateMatrix(self, Matrix, Weight):
        '''
        有序矩阵（符号矩阵）
        :param : 区间值矩阵
        :param Weight: 权重NormalizedMatrix
        :param o:定量类别
        :param c:定性类别
        :return:
        '''
        aii0 = []
        sum = [0, 0, 0, 0]
        eij = [0, 0, 0, 0]
        ei0j = [0, 0, 0, 0]
        max_index = 0
        min_index = 0

        aii0_max = ([0, 0], [0, 0])
        aii0_min = ([0, 0], [0, 0])

        for i in range(5):
            anext = []
            for i0 in range(5):
                sum[0], sum[1], sum[2], sum[3] = 0, 0, 0, 0
                sum_max = 0
                sum_min = 0
                for j in range(self.o):
                    eij[0] = Matrix[i][j][0][0]
                    eij[1] = Matrix[i][j][0][1]
                    eij[2] = Matrix[i][j][1][0]
                    eij[3] = Matrix[i][j][1][1]

                    ei0j[0] = Matrix[i0][j][0][0]
                    ei0j[1] = Matrix[i0][j][0][1]
                    ei0j[2] = Matrix[i0][j][1][0]
                    ei0j[3] = Matrix[i0][j][1][1]
                    for k in range(4):
                        if eij[k] - ei0j[k] == 0:
                            sum[k] = 0
                        else:
                            if eij[k] - ei0j[k] < 0:
                                sum[k] = -1.0 * Weight[j]
                                sum_min += 1
                            else:
                                sum[k] = 1.0 * Weight[j]
                                sum_max += 1
                    # 获取个体
                    sum_small = ([sum[0], sum[1]], [sum[2], sum[3]])
                    # 次方操作
                    sum_small = self.Exponentiation(sum_small, self.q, self.c0)
                    # 累加
                    if j == 0:
                        sum_avg = sum_small
                    else:
                        sum_avg = self.addition(sum_avg, sum_small, self.q)
                    # 获取最大最小因子
                    if max_index <= sum_max:
                        max_index = sum_max
                        aii0_max = sum_avg
                    if min_index <= sum_min:
                        min_index = sum_min
                        aii0_min = sum_avg
                # 次方操作
                sum_avg = self.Exponentiation(sum_avg, self.q, (1.0 / self.c0))

                # 计算好的矩阵进行存储
                anext.append(sum_avg)
            aii0.append(anext)
        return aii0, aii0_max, aii0_min

    def CalculatingMatrix(self, NormalizedMatrix, Weight):
        '''
        基本矩阵
        :param NormalizedMatrix: 区间值矩阵
        :param Weight: 权重
        :param o:定性类别
        :param c:定量类别
        :return:
        '''
        aii0 = []
        eij = [0, 0, 0, 0]
        ei0j = [0, 0, 0, 0]
        max_index = 0
        min_index = 0

        aii0_max = ([0, 0], [0, 0])
        aii0_min = ([0, 0], [0, 0])

        for i in range(5):
            anext = []
            for i0 in range(5):
                sum_max = 0
                sum_min = 0
                sum_avg = ([0, 0], [0, 0])
                for j in range(self.c0):
                    eij[0] = NormalizedMatrix[i][j][0][0]
                    eij[1] = NormalizedMatrix[i][j][0][1]
                    eij[2] = NormalizedMatrix[i][j][1][0]
                    eij[3] = NormalizedMatrix[i][j][1][1]

                    ei0j[0] = NormalizedMatrix[i0][j][0][0]
                    ei0j[1] = NormalizedMatrix[i0][j][0][1]
                    ei0j[2] = NormalizedMatrix[i0][j][1][0]
                    ei0j[3] = NormalizedMatrix[i0][j][1][1]

                    for k in range(4):
                        if eij[k] - ei0j[k] < 0:
                            sum_min += 1
                        else:
                            sum_max += 1
                    # 获取两个矩阵
                    eij_more = NormalizedMatrix[i][j]
                    ei0j_more = NormalizedMatrix[i0][j]
                    # 做差
                    sum_small = self.subtraction(eij_more, ei0j_more, self.q)
                    # 乘以权重
                    w = ([Weight[j], Weight[j]], [Weight[j], Weight[j]])
                    sum_small = self.multiplication(sum_small, w, self.q)
                    # 次方操作
                    sum_small = self.Exponentiation(sum_small, self.q, self.c0)
                    # 累加
                    if j == 0:
                        sum_avg = sum_small
                    else:
                        sum_avg = self.addition(sum_avg, sum_small, self.q)
                    # 获取最大最小因子
                    if max_index <= sum_max:
                        max_index = sum_max
                        aii0_max = sum_avg
                    if min_index <= sum_min:
                        min_index = sum_min
                        aii0_min = sum_avg
                # 次方操作
                sum_avg = self.Exponentiation(sum_avg, self.q, (1.0 / self.c0))
                # 存储
                anext.append(sum_avg)
            aii0.append(anext)
        return aii0, aii0_max, aii0_min

    def DifferentialSuperiorityRate(self, Matrix, a_max, a_min):
        '''
        微分有序矩阵
        :param Matrix: 区间值矩阵
        :param a_max:最大值区间
        :param a_min:最小值区间
        :return:
        '''

        dii0 = []
        down = self.subtraction(a_max, a_min, self.q)
        for i in range(5):
            result = []
            for i0 in range(5):
                up = self.subtraction(Matrix[i][i0], a_min, self.q)
                div = self.division(up, down, self.q)
                result.append(div)
            dii0.append(result)
        return dii0

    def DifferentialCardinal(self, Matrix, a_max, a_min):
        '''
        微分基本矩阵
        :param Matrix: 区间值矩阵
        :param a_max:最大值区间
        :param a_min:最小值区间
        :return:
        '''

        dii0 = []
        down = self.subtraction(a_max, a_min, self.q)
        for i in range(5):
            result = []
            for i0 in range(5):
                up = self.subtraction(Matrix[i][i0], a_min, self.q)
                div = self.division(up, down, self.q)
                result.append(div)
            dii0.append(result)
        return dii0

    def getFinalUtilityScore(self, Si):
        '''
        获取最终效用得分
        :param Si: 得分区间
        :param Weight: 权重
        :return:
        '''
        U = []
        for i in range(5):
            U.append(self.getscore(Si[i]))
        return U

    def TotalDominance(self, SMatrix, DMatrix, weight):
        '''
        完全优势计算
        :param SMatrix: 微分优势矩阵
        :param DMatrix: 微分基本矩阵
        :param weight: 权重
        :return:
        '''
        wo, wc = 0, 0
        Dii0 = []
        # 累计wo,wc
        for i in range(self.o):
            wo += weight[i]
        for i in range(self.c0):
            wc += weight[i]
        wo_sum = ([wo, wo], [wo, wo])
        wc_sum = ([wc, wc], [wc, wc])
        # 求Dii0
        for i in range(5):
            Dnext = []
            for i0 in range(5):
                left = self.multiplication(wo_sum, SMatrix[i][i0], self.q)
                right = self.multiplication(wc_sum, DMatrix[i][i0], self.q)
                D = self.addition(left, right, self.q)
                Dnext.append(D)
            Dii0.append(Dnext)
        # 求优势S
        S = []
        sum = ([0, 0], [0, 0])
        for i in range(5):
            for i0 in range(5):
                right = self.division(Dii0[i0][i], Dii0[i][i0], self.q)
                if (i0 == 0):
                    sum = right
                else:
                    sum = self.addition(sum, right, self.q)
            sum = self.Exponentiation(sum, self.q, -1)
            S.append(sum)
        return S, Dii0

    def getscore(self, IVq):
        '''
        我们提出的得分函数
        :param IVq:区间值
        :param q:q值
        :return:
        '''
        a = IVq[0][0]
        b = IVq[0][1]
        c = IVq[1][0]
        d = IVq[1][1]
        return (m.log(math.fabs(a + b + c + d + 1)) + (b - a) + (d - c) ** 2 + (a - c + b - d) * m.log(3) / 2) / (
                    3 * m.log(3))

    def getResult(self):
        '''
        最终结果
        :param Matrix:
        :param q:
        :return:
        '''

        # 计算优势矩阵
        SMatrix, smax, smin = self.SuperiorityRateMatrix(self.matrix, self.weight)
        # 计算基本矩阵
        CMatrix, cmax, cmin = self.CalculatingMatrix(self.matrix, self.weight)
        # 微分优势矩阵
        DSMatrix = self.DifferentialSuperiorityRate(SMatrix, smax, smin)
        # 微分基本矩阵
        DCMatrix = self.DifferentialCardinal(CMatrix, cmax, cmin)
        # 完全优势计算
        Si, SiMatrix = self.TotalDominance(DSMatrix, DCMatrix, self.weight)
        U = self.getFinalUtilityScore(Si)
        U = [i / sum(U) for i in U]
        return U


if __name__ == "__main__":
    Matrix = np.array([[([0.58, 0.75], [0.1, 0.2]), ([0.7, 0.78], [0.2, 0.3]), ([0.5, 0.78], [0.1, 0.2]),
                        ([0.65, 0.7], [0.3, 0.35]), ([0.4, 0.5], [0.5, 0.6])],
                       [([0.5, 0.6], [0.1, 0.2]), ([0.75, 0.78], [0.2, 0.3]), ([0.6, 0.78], [0.1, 0.15]),
                        ([0.7, 0.8], [0.2, 0.3]), ([0.5, 0.6], [0.4, 0.5])],
                       [([0.5, 0.78], [0.1, 0.2]), ([0.6, 0.7], [0.3, 0.4]), ([0.7, 0.78], [0.2, 0.3]),
                        ([0.6, 0.7], [0.3, 0.4]),
                        ([0.35, 0.45], [0.5, 0.65])],
                       [([0.75, 0.780], [0.2, 0.3]), ([0.6, 0.75], [0.2, 0.3]), ([0.7, 0.78], [0.2, 0.3]),
                        ([0.55, 0.65], [0.3, 0.4]), ([0.35, 0.4], [0.6, 0.65])],
                       [([0.6, 0.75], [0.3, 0.4]), ([0.5, 0.6], [0.4, 0.5]), ([0.6, 0.7], [0.3, 0.4]),
                        ([0.5, 0.6], [0.4, 0.5]),
                        ([0.1, 0.2], [0.4, 0.5])]])
    weight = (0.1, 0.15, 0.2, 0.25, 0.3)
    # weight = (0.2, 0.2, 0.2, 0.2, 0.2)
    evamix = EVAMIX(Matrix, weight, 1)
    result = evamix.getResult()
    print(f'U={np.round(result, 8)}')   #print字符串前面加f表示格式化字符串，加f后可以在字符串里面使用用花括号括起来的变量和表达式
